﻿using System;
using System.Globalization;
using Com.Lancetinc.Evs.Models;
using NLog;

namespace Com.Lancetinc.Evs.Communications
{
    public static class PacketHelper
    {
        private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 握手协议
        /// </summary>
        /// <returns></returns>
        public static Packet CreateConnect()
        {
            return new Packet(CtrlCmds.CONNECT);
        }

        /// <summary>
        /// 节拍协议
        /// </summary>
        /// <returns></returns>
        public static Packet CreateBeat()
        {
            return new Packet(CtrlCmds.BEAT);
        }

        /// <summary>
        /// 状态协议
        /// </summary>
        /// <returns></returns>
        public static Packet CreateState()
        {
            var nowSeconds = (long)Math.Round(DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
            return new Packet(CtrlCmds.STATE, nowSeconds.ToString().PadLeft(10, '0'));
        }

        public static Packet CreateReadFirstRunTime()
        {
            return new Packet(CtrlCmds.READ_FIRST_RUN_TIME);
        }

        public static Packet CreateLed(int ledBrightness)
        {
            return new Packet(CtrlCmds.LED, $"{(char)('0' + ledBrightness)}");
        }

        /// <summary>
        /// 解码仪器信息
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        public static IReceivedInstrumentState DecodeInstrumentState(Packet packet)
        {
            var data = packet.Data;
            var orgBytes = packet.OrgBytes;
            if (data == null || data.Length != 22)
            {
                throw new CommInvalidDataException("invalid state:" + data);
            }

            var index = 0;
            var info = new GenericReceivedInstrumentState
            {
                //内窥镜连接状态
                EndoscopicConnected = data[index] == '1'
            };
            index += 1;

            var parsedItem = "";
            try
            {
                parsedItem = "ErrorCode";
                // 错误状态
                info.ErrorCode = (byte)(data[index] - '0');
                // 内窥镜连接异常的时候，后续数据可能是乱码的，没必要解析
                if (!info.EndoscopicConnected)
                {
                    parsedItem = "LedBrightness";
                    info.LedBrightness = (byte)(data[data.Length - 1] - '0');
                    return info;
                }
                index += 1;

                if (!IsAllFF(orgBytes, index, 10))
                {
                    parsedItem = "FactoryTime";
                    // POSIX时间(秒）10位
                    var factoryTimeStr = data.Substring(index, 10);
                    info.FactoryTime = new DateTime(1970, 1, 1).AddSeconds(long.Parse(factoryTimeStr, NumberStyles.None));
                }
                index += 10;

                parsedItem = "VideoRotate";
                // 图像翻转指令
                info.VideoRotate = (EnumVideoRotate)data[index];
                index += 1;

                if (!IsAllFF(orgBytes, index, 6))
                {
                    parsedItem = "HcSerialNo";
                    // 耗材十六进制序列号值 6位
                    info.HcSerialNo = data.Substring(index, 6);
                }

                index += 6;

                if (!IsAllFF(orgBytes, index, 2))
                {
                    parsedItem = "HcUsedTime";
                    // 下位机耗材模块运行时间，2位
                    var useTime = int.Parse(data.Substring(index, 2), NumberStyles.HexNumber);
                    if (useTime == 0xFF)
                        useTime = 0;
                    info.HcUsedTime = useTime;
                }

                index += 2;

                parsedItem = "LedBrightness";
                // LED灯亮度等级 1位
                info.LedBrightness = (byte)(data[index] - '0');
                if (info.LedBrightness > AppConsts.MaxLedBrightness)
                {
                    info.LedBrightness = AppConsts.MaxLedBrightness;
                }
            }
            catch (Exception ex)
            {
                throw new CommInvalidDataException($"failed to parse {parsedItem}, data={data}, error={ex.Message}");
            }

            return info;
        }

        private static bool IsAllFF(byte[] bytes, int start, int len)
        {
            for (int i = start; i < start + len; i++)
            {
                if (bytes[i] != 0xFF)
                    return false;
            }

            return true;
        }

        public static DateTime DecodeReadFirstRunTime(Packet packet)
        {
            try
            {
                // POSIX时间(秒）10位
                var timeStr = packet.Data;
                return new DateTime(1970, 1, 1).AddSeconds(long.Parse(timeStr, NumberStyles.None));
            }
            catch (FormatException e)
            {
                Logger.Error(e, "Data:" + packet.Data);
                return DateTime.MinValue;
            }
        }

        public static InstButtonActions DecodeButton(Packet packet)
        {
            try
            {
                return (InstButtonActions)int.Parse(packet.Data);
            }
            catch (FormatException e)
            {
                Logger.Error(e, "Data:" + packet.Data);
                return 0;
            }
            catch (OverflowException e)
            {
                Logger.Error(e, "Data:" + packet.Data);
                return 0;
            }
        }
    }
}